////////////////////////////////////////////////////////////////////////////////
///
///  \brief A C++ interface to gnuplot.
///
///
///  The interface uses pipes and so won't run on a system that doesn't have
///  POSIX pipe support Tested on Windows (MinGW and Visual C++) and Linux (GCC)
///
/// Version history:
/// 0. C interface
///    by N. Devillard (27/01/03)
/// 1. C++ interface: direct translation from the C interface
///    by Rajarshi Guha (07/03/03)
/// 2. corrections for Win32 compatibility
///    by V. Chyzhdzenka (20/05/03)
/// 3. some member functions added, corrections for Win32 and Linux 
///    compatibility 
///    by M. Burgis (10/03/08)
///
/// Requirements:
/// * gnuplot has to be installed (http://www.gnuplot.info/download.html)
/// * for Windows: set Path-Variable for Gnuplot path 
///         (e.g. C:/program files/gnuplot/bin)
///         or set Gnuplot path with: 
///         Gnuplot::set_GNUPlotPath(const std::string &path);
///
////////////////////////////////////////////////////////////////////////////////


#ifndef _GNUPLOT_PIPES_H_
#define _GNUPLOT_PIPES_H_


#include <iostream>
#include <string>
#include <vector>
#include <fstream>  
#include <sstream>              // for std::ostringstream
#include <stdexcept> 
#include <cstdio>     
#include <cstdlib>              // for getenv()
#include <list>                 // for std::list


#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) 
//defined for 32 and 64-bit environments
 #include <io.h>                // for _access(), _mktemp()
 #define GP_MAX_TMP_FILES  27   // 27 temporary files it's Microsoft restriction
#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) 
//all UNIX-like OSs (Linux, *BSD, MacOSX, Solaris, ...)
 #include <unistd.h>            // for access(), mkstemp()
 #define GP_MAX_TMP_FILES  64
#else
 #error unsupported or unknown operating system
#endif

//declare classes in global namespace


class GnuplotException : public std::runtime_error
{
    public:
        GnuplotException(const std::string &msg) : std::runtime_error(msg){}
};



class Gnuplot
{
    private:

    //----------------------------------------------------------------------------------
    // member data
	///\brief pointer to the stream that can be used to write to the pipe
        FILE                    *gnucmd; 
	///\brief validation of gnuplot session      
        bool                     valid;  
	///\brief true = 2d, false = 3d      
        bool                     two_dim;  
	///\brief number of plots in session   
        int                      nplots;  
  	///\brief functions and data are displayed in a defined styles   
        std::string              pstyle;  
  	///\brief interpolate and approximate data in defined styles (e.g. spline)
        std::string              smooth;    
  	///\brief list of created tmpfiles   
        std::vector<std::string> tmpfile_list; 

    //----------------------------------------------------------------------------------
    // static data
	///\brief number of all tmpfiles (number of tmpfiles restricted)
        static int               tmpfile_num;   
	///\brief name of executed GNUPlot file     
        static std::string       m_sGNUPlotFileName; 
	///\brief gnuplot path
        static std::string       m_sGNUPlotPath;
	///\brief standart terminal, used by showonscreen     
        static std::string       terminal_std;       

    //----------------------------------------------------------------------------------
    // member functions (auxiliary functions)
	// ---------------------------------------------------
	///\brief get_program_path(); and popen();
	///
	/// \param --> void
	/// 
	/// \return <-- void
	// ---------------------------------------------------
        void           init(); 
	// ---------------------------------------------------
	///\brief creates tmpfile and returns its name   
	/// 
	/// \param tmp --> points to the tempfile
	/// 
	/// \return <-- the name of the tempfile
	// ---------------------------------------------------                          
        std::string    create_tmpfile(std::ofstream &tmp);  

    //----------------------------------------------------------------------------------
	///\brief gnuplot path found?
	///
	/// \param ---
	///
	/// \return <-- found the gnuplot path (yes == true, no == false)
	// ---------------------------------------------------------------------------------
    static bool    get_program_path(); 
	
	// ---------------------------------------------------------------------------------
	///\brief checks if file is available
	///
	/// \param filename --> the filename
	/// \param mode 	--> the mode [optional,default value = 0]
	///
	/// \return file exists (yes == true, no == false)
	// ---------------------------------------------------------------------------------                                  
    bool file_available(const std::string &filename);
      
	// ---------------------------------------------------------------------------------
	///\brief checks if file exists
	///
	/// \param filename --> the filename
	/// \param mode 	--> the mode [optional,default value = 0]
	///
	/// \return file exists (yes == true, no == false)
	// ---------------------------------------------------------------------------------                                  
    static bool    file_exists(const std::string &filename, int mode=0); 

    public:

		// ----------------------------------------------------------------------------
        /// \brief optional function: set Gnuplot path manual
        /// attention:  for windows: path with slash '/' not backslash '\'
		/// 
		/// \param path --> the gnuplot path
		///
		/// \return true on success, false otherwise
		// ----------------------------------------------------------------------------
        static bool set_GNUPlotPath(const std::string &path);


		// ----------------------------------------------------------------------------
        /// optional: set standart terminal, used by showonscreen
        ///   defaults: Windows - win, Linux - x11, Mac - aqua
		/// 
		/// \param type --> the terminal type
		///
		/// \return ---
		// ----------------------------------------------------------------------------
        static void set_terminal_std(const std::string &type);

    	//-----------------------------------------------------------------------------
    	// constructors
		// ----------------------------------------------------------------------------

	    ///\brief set a style during construction
        Gnuplot(const std::string &style = "points");

        /// plot a single std::vector at one go
        Gnuplot(const std::vector<double> &x,
                const std::string &title = "",
                const std::string &style = "points",
                const std::string &labelx = "x",
                const std::string &labely = "y");

         /// plot pairs std::vector at one go
        Gnuplot(const std::vector<double> &x,
                const std::vector<double> &y,
                const std::string &title = "",
                const std::string &style = "points",
                const std::string &labelx = "x",
                const std::string &labely = "y");

         /// plot triples std::vector at one go
        Gnuplot(const std::vector<double> &x,
                const std::vector<double> &y,
                const std::vector<double> &z,
                const std::string &title = "",
                const std::string &style = "points",
                const std::string &labelx = "x",
                const std::string &labely = "y",
                const std::string &labelz = "z");

         /// destructor: needed to delete temporary files
        ~Gnuplot();


    //----------------------------------------------------------------------------------

    /// send a command to gnuplot
        Gnuplot& cmd(const std::string &cmdstr);
	// ---------------------------------------------------------------------------------
	///\brief Sends a command to an active gnuplot session, identical to cmd()
	/// send a command to gnuplot using the <<  operator
	///
	/// \param cmdstr --> the command string
	/// 
	/// \return <-- a reference to the gnuplot object	
	// ---------------------------------------------------------------------------------
    inline Gnuplot& operator<<(const std::string &cmdstr){
        cmd(cmdstr);
        return(*this);
    }



    //----------------------------------------------------------------------------------
    // show on screen or write to file

    /// sets terminal type to terminal_std
    Gnuplot& showonscreen(); // window output is set by default (win/x11/aqua)

    /// saves a gnuplot session to a postscript file, filename without extension
    Gnuplot& savetops(const std::string &filename = "gnuplot_output");


    //----------------------------------------------------------------------------------
    // set and unset

    /// set line style (some of these styles require additional information):
    ///  lines, points, linespoints, impulses, dots, steps, fsteps, histeps,
    ///  boxes, histograms, filledcurves
    Gnuplot& set_style(const std::string &stylestr = "points");

	Gnuplot& set_lineStyle(const unsigned int styleNum, const unsigned int lineType, const unsigned int width, const std::string color);

    /// interpolation and approximation of data, arguments:
    ///  csplines, bezier, acsplines (for data values > 0), sbezier, unique, frequency
    /// (works only with plot_x, plot_xy, plotfile_x, plotfile_xy
    /// (if smooth is set, set_style has no effekt on data plotting)
    Gnuplot& set_smooth(const std::string &stylestr = "csplines");

    // ----------------------------------------------------------------------
    /// \brief unset smooth
    /// attention: smooth is not set by default
    /// 
    /// \param ---
    /// 
    /// \return <-- a reference to a gnuplot object
    // ----------------------------------------------------------------------
    inline Gnuplot& unset_smooth(){ smooth = ""; return *this;}; 


    /// scales the size of the points used in plots
    Gnuplot& set_pointsize(const double pointsize = 1.0);

    /// turns grid on/off
    inline Gnuplot& set_grid()	{cmd("set grid");return *this;};
    /// grid is not set by default	
    inline Gnuplot& unset_grid(){cmd("unset grid");return *this;}; 

    // -----------------------------------------------
    /// set the mulitplot mode
    /// 
    /// \param ---
    ///
    /// \return <-- reference to the gnuplot object
    // -----------------------------------------------
    inline Gnuplot& set_multiplot(){cmd("set multiplot") ;return *this;};

    // -----------------------------------------------
    /// unsets the mulitplot mode
    /// 
    /// \param ---
    ///
    /// \return <-- reference to the gnuplot object
    // -----------------------------------------------
    inline Gnuplot& unset_multiplot(){cmd("unset multiplot");return *this;};
    


    /// set sampling rate of functions, or for interpolating data
    Gnuplot& set_samples(const int samples = 100);
    /// set isoline density (grid) for plotting functions as surfaces (for 3d plots)
    Gnuplot& set_isosamples(const int isolines = 10);

    // --------------------------------------------------------------------------
    /// enables/disables hidden line removal for surface plotting (for 3d plot)
    ///
    /// \param ---
    ///
    /// \return <-- reference to the gnuplot object
    // --------------------------------------------------------------------------
    Gnuplot& set_hidden3d(){cmd("set hidden3d");return *this;};

    // ---------------------------------------------------------------------------
    /// hidden3d is not set by default
    ///
    /// \param ---
    ///
    /// \return <-- reference to the gnuplot object
    // ---------------------------------------------------------------------------
    inline Gnuplot& unset_hidden3d(){cmd("unset hidden3d"); return *this;}; 

    /// enables/disables contour drawing for surfaces (for 3d plot)
    ///  base, surface, both
    Gnuplot& set_contour(const std::string &position = "base");
    // --------------------------------------------------------------------------
    /// contour is not set by default, it disables contour drawing for surfaces
    ///
    /// \param ---
    ///
    /// \return <-- reference to the gnuplot object
    // ------------------------------------------------------------------
    inline Gnuplot& unset_contour(){cmd("unset contour");return *this;};

    // ------------------------------------------------------------
    /// enables/disables the display of surfaces (for 3d plot)
    ///
    /// \param ---	
    ///
    /// \return <-- reference to the gnuplot object
    // ------------------------------------------------------------------
    inline Gnuplot& set_surface(){cmd("set surface");return *this;}; 

    // ----------------------------------------------------------
    /// surface is set by default,
    /// it disables the display of surfaces (for 3d plot)
    ///
    /// \param ---	
    ///
    /// \return <-- reference to the gnuplot object
    // ------------------------------------------------------------------
    inline Gnuplot& unset_surface(){cmd("unset surface"); return *this;}


    /// switches legend on/off
    /// position: inside/outside, left/center/right, top/center/bottom, nobox/box
    Gnuplot& set_legend(const std::string &position = "default"); 

    // ------------------------------------------------------------------
    /// \brief  Switches legend off
    /// attention:legend is set by default
    ///
    /// \param ---	
    ///
    /// \return <-- reference to the gnuplot object
    // ------------------------------------------------------------------
    inline Gnuplot& unset_legend(){cmd("unset key"); return *this;}

    // ----------------------------------------------------------------------- 
    /// \brief sets and clears the title of a gnuplot session
    ///
    /// \param title --> the title of the plot [optional, default == ""]
    ///
    /// \return <-- reference to the gnuplot object
    // ----------------------------------------------------------------------- 
    inline Gnuplot& set_title(const std::string &title = "")
    {
        std::string cmdstr;
        cmdstr = "set title \"";
        cmdstr+=title;
        cmdstr+="\"";
        *this<<cmdstr;
        return *this;
    }

    //----------------------------------------------------------------------------------
    ///\brief Clears the title of a gnuplot session
    /// The title is not set by default.
    ///
    /// \param ---
    ///
    /// \return <-- reference to the gnuplot object
    // ---------------------------------------------------------------------------------
    inline Gnuplot& unset_title(){this->set_title();return *this;}


    /// set x axis label
    Gnuplot& set_ylabel(const std::string &label = "x");
    /// set y axis label
    Gnuplot& set_xlabel(const std::string &label = "y");
    /// set z axis label
    Gnuplot& set_zlabel(const std::string &label = "z");

    /// set axis - ranges
    Gnuplot& set_xrange(const double iFrom,
                        const double iTo);
    /// set y-axis - ranges
    Gnuplot& set_yrange(const double iFrom,
                        const double iTo);
    /// set z-axis - ranges
    Gnuplot& set_zrange(const double iFrom,
                        const double iTo);
    /// autoscale axis (set by default) of xaxis
    /// 
    /// \param ---
    ///
    /// \return <-- reference to the gnuplot object
    // -----------------------------------------------
    inline Gnuplot& set_xautoscale(){cmd("set xrange restore");cmd("set autoscale x");return *this;};

    // -----------------------------------------------
    /// autoscale axis (set by default) of yaxis
    /// 
    /// \param ---
    ///
    /// \return <-- reference to the gnuplot object
    // -----------------------------------------------
    inline Gnuplot& set_yautoscale(){cmd("set yrange restore");cmd("set autoscale y");return *this;};

    // -----------------------------------------------
    /// autoscale axis (set by default) of zaxis
    /// 
    /// \param ---
    ///
    /// \return <-- reference to the gnuplot object
    // -----------------------------------------------
    inline Gnuplot& set_zautoscale(){cmd("set zrange restore");cmd("set autoscale z");return *this;};


    /// turns on/off log scaling for the specified xaxis (logscale is not set by default)
    Gnuplot& set_xlogscale(const double base = 10);
    /// turns on/off log scaling for the specified yaxis (logscale is not set by default)
    Gnuplot& set_ylogscale(const double base = 10);
    /// turns on/off log scaling for the specified zaxis (logscale is not set by default)
    Gnuplot& set_zlogscale(const double base = 10);

    // ----------------------------------------------- 
    /// turns off log scaling for the x axis
    /// 
    /// \param ---
    ///
    /// \return <-- reference to the gnuplot object
    // -----------------------------------------------	
    inline Gnuplot& unset_xlogscale(){cmd("unset logscale x"); return *this;};

    // ----------------------------------------------- 
    /// turns off log scaling for the y axis
    /// 
    /// \param ---
    ///
    /// \return <-- reference to the gnuplot object
    // -----------------------------------------------	
    inline Gnuplot& unset_ylogscale(){cmd("unset logscale y"); return *this;};

    // ----------------------------------------------- 
    /// turns off log scaling for the z axis
    /// 
    /// \param ---
    ///
    /// \return <-- reference to the gnuplot object
    // -----------------------------------------------		
    inline Gnuplot& unset_zlogscale(){cmd("unset logscale z"); return *this;};


    /// set palette range (autoscale by default)
    Gnuplot& set_cbrange(const double iFrom, const double iTo);


    //----------------------------------------------------------------------------------
    // plot

    /// plot a single std::vector: x
    ///   from file
    Gnuplot& plotfile_x(const std::string &filename,
                        const unsigned int column = 1,
                        const std::string &title = "");
    ///   from std::vector
    template<typename X>
    Gnuplot& plot_x(const X& x, const std::string &title = "");


    /// plot x,y pairs: x y
    ///   from file
    Gnuplot& plotfile_xy(const std::string &filename,
                         const unsigned int column_x = 1,
                         const unsigned int column_y = 2,
                         const std::string &title = "",
						 const unsigned int linestyle = 1);
    ///   from data
    template<typename X, typename Y>
    Gnuplot& plot_xy(const X& x, const Y& y, const std::string &title = "", const unsigned int linestyle = 1);


    /// plot x,y pairs with dy errorbars: x y dy
    ///   from file
    Gnuplot& plotfile_xy_err(const std::string &filename,
                             const unsigned int column_x  = 1,
                             const unsigned int column_y  = 2,
                             const unsigned int column_dy = 3,
                             const std::string &title = "");
    ///   from data
    template<typename X, typename Y, typename E>
    Gnuplot& plot_xy_err(const X &x, const Y &y, const E &dy,
                         const std::string &title = "");


    /// plot x,y,z triples: x y z
    ///   from file
    Gnuplot& plotfile_xyz(const std::string &filename,
                          const unsigned int column_x = 1,
                          const unsigned int column_y = 2,
                          const unsigned int column_z = 3,
                          const std::string &title = "");
    ///   from std::vector
    template<typename X, typename Y, typename Z>
    Gnuplot& plot_xyz(const X &x,
                      const Y &y,
                      const Z &z,
                      const std::string &title = "");

	Gnuplot& plotfile_vectors(const std::string &filename,
								   const unsigned int column_x,
								   const unsigned int column_y,
								   const unsigned int column_dx,
								   const unsigned int column_dy,
                                   const std::string &title = "");

	template<typename X, typename Y, typename DX, typename DY>
	Gnuplot& plot_vectors(const X &x,
                           const Y &y,
                           const DX &dx,
						   const DY &dy,
                           const std::string &title = "");



    /// plot an equation of the form: y = ax + b, you supply a and b
    Gnuplot& plot_slope(const double a,
                        const double b,
                        const std::string &title = "");


    /// plot an equation supplied as a std::string y=f(x), write only the function f(x) not y=
    /// the independent variable has to be x
    /// binary operators: ** exponentiation, * multiply, / divide, + add, - substract, % modulo
    /// unary operators: - minus, ! factorial
    /// elementary functions: rand(x), abs(x), sgn(x), ceil(x), floor(x), int(x), imag(x), real(x), arg(x),
    ///   sqrt(x), exp(x), log(x), log10(x), sin(x), cos(x), tan(x), asin(x), acos(x), atan(x), atan2(y,x),
    ///   sinh(x), cosh(x), tanh(x), asinh(x), acosh(x), atanh(x)
    /// special functions: erf(x), erfc(x), inverf(x), gamma(x), igamma(a,x), lgamma(x), ibeta(p,q,x),
    ///   besj0(x), besj1(x), besy0(x), besy1(x), lambertw(x)
    /// statistical fuctions: norm(x), invnorm(x)
    Gnuplot& plot_equation(const std::string &equation,
                           const std::string &title = "");

    /// plot an equation supplied as a std::string z=f(x,y), write only the function f(x,y) not z=
    /// the independent variables have to be x and y
    Gnuplot& plot_equation3d(const std::string &equation,
                             const std::string &title = "");


    /// plot image
    Gnuplot& plot_image(const unsigned char *ucPicBuf,
                        const unsigned int iWidth,
                        const unsigned int iHeight,
                        const std::string &title = "");


    //----------------------------------------------------------------------------------
    ///\brief replot repeats the last plot or splot command.
    ///  this can be useful for viewing a plot with different set options,
    ///  or when generating the same plot for several devices (showonscreen, savetops)
    /// 
    /// \param ---
    ///
    /// \return ---
    //----------------------------------------------------------------------------------
    inline Gnuplot& replot(void){if (nplots > 0) cmd("replot");return *this;};

    /// resets a gnuplot session (next plot will erase previous ones)
    Gnuplot& reset_plot();

    /// resets a gnuplot session and sets all variables to default
    Gnuplot& reset_all();

    /// deletes temporary files
    void remove_tmpfiles();

    // -------------------------------------------------------------------
    /// \brief Is the gnuplot session valid ??
    /// 
    ///
    /// \param ---
    /// 
    /// \return true if valid, false if not
    // ------------------------------------------------------------------- 
    inline bool is_valid(){return(valid);};
};

//------------------------------------------------------------------------------
//
// initialize static data
//
int Gnuplot::tmpfile_num = 0;

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__)
std::string Gnuplot::m_sGNUPlotFileName = "pgnuplot.exe";
std::string Gnuplot::m_sGNUPlotPath = "C:/gnuplot/binary";
#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
std::string Gnuplot::m_sGNUPlotFileName = "gnuplot";
std::string Gnuplot::m_sGNUPlotPath = "/usr/local/bin/";
#endif

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__)
std::string Gnuplot::terminal_std = "windows";
#elif ( defined(unix) || defined(__unix) || defined(__unix__) ) && !defined(__APPLE__)
std::string Gnuplot::terminal_std = "x11";
#elif defined(__APPLE__)
std::string Gnuplot::terminal_std = "aqua";
#endif

//------------------------------------------------------------------------------
//
// constructor: set a style during construction
//
inline Gnuplot::Gnuplot(const std::string &style)
			   :gnucmd(NULL) ,valid(false) ,two_dim(false) ,nplots(0)

{
    init();
    set_style(style);
}
  
//------------------------------------------------------------------------------
//
// constructor: open a new session, plot a signal (x)
//
inline Gnuplot::Gnuplot(const std::vector<double> &x,
                 const std::string &title,
                 const std::string &style,
                 const std::string &labelx,
                 const std::string &labely)
			   :gnucmd(NULL) ,valid(false) ,two_dim(false) ,nplots(0)
{
    init();

    set_style(style);
    set_xlabel(labelx);
    set_ylabel(labely);

    plot_x(x,title);
}


//------------------------------------------------------------------------------
//
// constructor: open a new session, plot a signal (x,y)
//
inline Gnuplot::Gnuplot(const std::vector<double> &x,
                 const std::vector<double> &y,
                 const std::string &title,
                 const std::string &style,
                 const std::string &labelx,
                 const std::string &labely)
			   :gnucmd(NULL) ,valid(false) ,two_dim(false) ,nplots(0)
{
    init();

    set_style(style);
    set_xlabel(labelx);
    set_ylabel(labely);

    plot_xy(x,y,title);
}


//------------------------------------------------------------------------------
//
// constructor: open a new session, plot a signal (x,y,z)
//
inline Gnuplot::Gnuplot(const std::vector<double> &x,
                 const std::vector<double> &y,
                 const std::vector<double> &z,
                 const std::string &title,
                 const std::string &style,
                 const std::string &labelx,
                 const std::string &labely,
                 const std::string &labelz)
			   :gnucmd(NULL) ,valid(false) ,two_dim(false) ,nplots(0)
{
    init();

    set_style(style);
    set_xlabel(labelx);
    set_ylabel(labely);
    set_zlabel(labelz);

    plot_xyz(x,y,z,title);
}


//------------------------------------------------------------------------------
//
/// Plots a 2d graph from a list of doubles: x
//
template<typename X>
Gnuplot& Gnuplot::plot_x(const X& x, const std::string &title)
{
    if (x.size() == 0)
    {
        throw GnuplotException("std::vector too small");
        return *this;
    }

    std::ofstream tmp;
    std::string name = create_tmpfile(tmp);
    if (name == "")
        return *this;

    //
    // write the data to file
    //
    for (unsigned int i = 0; i < x.size(); i++)
        tmp << x[i] << std::endl;

    tmp.flush();
    tmp.close();


    plotfile_x(name, 1, title);

    return *this;
}

  
//------------------------------------------------------------------------------
//
/// Plots a 2d graph from a list of doubles: x y
//
template<typename X, typename Y>
Gnuplot& Gnuplot::plot_xy(const X& x, const Y& y, const std::string &title, const unsigned int linestyle)
{
    if (x.size() == 0 || y.size() == 0)
    {
        throw GnuplotException("std::vectors too small");
        return *this;
    }

    if (x.size() != y.size())
    {
        throw GnuplotException("Length of the std::vectors differs");
        return *this;
    }


    std::ofstream tmp;
    std::string name = create_tmpfile(tmp);
    if (name == "")
        return *this;

    //
    // write the data to file
    //
    for (unsigned int i = 0; i < x.size(); i++)
        tmp << x[i] << " " << y[i] << std::endl;

    tmp.flush();
    tmp.close();


    plotfile_xy(name, 1, 2, title, linestyle);

    return *this;
}

///-----------------------------------------------------------------------------
///
/// plot x,y pairs with dy errorbars
///
template<typename X, typename Y, typename E>
Gnuplot& Gnuplot::plot_xy_err(const X &x,
                              const Y &y,
                              const E &dy,
                              const std::string &title)
{
    if (x.size() == 0 || y.size() == 0 || dy.size() == 0)
    {
        throw GnuplotException("std::vectors too small");
        return *this;
    }

    if (x.size() != y.size() || y.size() != dy.size())
    {
        throw GnuplotException("Length of the std::vectors differs");
        return *this;
    }


    std::ofstream tmp;
    std::string name = create_tmpfile(tmp);
    if (name == "")
        return *this;

    //
    // write the data to file
    //
    for (unsigned int i = 0; i < x.size(); i++)
        tmp << x[i] << " " << y[i] << " " << dy[i] << std::endl;

    tmp.flush();
    tmp.close();


    // Do the actual plot
    plotfile_xy_err(name, 1, 2, 3, title);

    return *this;
}


//------------------------------------------------------------------------------
//
// Plots a 3d graph from a list of doubles: x y z
//
template<typename X, typename Y, typename Z>
Gnuplot& Gnuplot::plot_xyz(const X &x,
                           const Y &y,
                           const Z &z,
                           const std::string &title)
{
    if (x.size() == 0 || y.size() == 0 || z.size() == 0)
    {
        throw GnuplotException("std::vectors too small");
        return *this;
    }

    if (x.size() != y.size() || x.size() != z.size())
    {
        throw GnuplotException("Length of the std::vectors differs");
        return *this;
    }


    std::ofstream tmp;
    std::string name = create_tmpfile(tmp);
    if (name == "")
        return *this;

    //
    // write the data to file
    //
    for (unsigned int i = 0; i < x.size(); i++)
        tmp << x[i] << " " << y[i] << " " << z[i] <<std::endl;

    tmp.flush();
    tmp.close();


    plotfile_xyz(name, 1, 2, 3, title);

    return *this;
}

template<typename X, typename Y, typename DX, typename DY>
Gnuplot& Gnuplot::plot_vectors(const X &x,
                           const Y &y,
                           const DX &dx,
						   const DY &dy,
                           const std::string &title)
{
    if (x.size() == 0 || y.size() == 0 || dx.size() == 0 || dy.size() == 0)
    {
        throw GnuplotException("std::vectors too small");
        return *this;
    }

    if (x.size() != y.size() || x.size() != dx.size() || dy.size() != x.size())
    {
        throw GnuplotException("Length of the std::vectors differs");
        return *this;
    }


    std::ofstream tmp;
    std::string name = create_tmpfile(tmp);
    if (name == "")
        return *this;

    //
    // write the data to file
    //
    for (unsigned int i = 0; i < x.size(); i++)
        tmp << x[i] << " " << y[i] << " " << dx[i] << " " << dy[i] <<std::endl;

    tmp.flush();
    tmp.close();

	plotfile_vectors(name, 1, 2, 3, 4, title);

    return *this;
}


//------------------------------------------------------------------------------
//
// define static member function: set Gnuplot path manual
//   for windows: path with slash '/' not backslash '\'
//
bool Gnuplot::set_GNUPlotPath(const std::string &path)
{

    std::string tmp = path + "/" + Gnuplot::m_sGNUPlotFileName;


#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__)
    if ( Gnuplot::file_exists(tmp,0) ) // check existence
#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
    if ( Gnuplot::file_exists(tmp,1) ) // check existence and execution permission
#endif
    {
        Gnuplot::m_sGNUPlotPath = path;
        return true;
    }
    else
    {
        Gnuplot::m_sGNUPlotPath.clear();
        return false;
    }
}


//------------------------------------------------------------------------------
//
// define static member function: set standart terminal, used by showonscreen
//  defaults: Windows - win, Linux - x11, Mac - aqua
//
void Gnuplot::set_terminal_std(const std::string &type)
{
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
    if (type.find("x11") != std::string::npos && getenv("DISPLAY") == NULL)
    {
        throw GnuplotException("Can't find DISPLAY variable");
    }
#endif


    Gnuplot::terminal_std = type;
    return;
}


//------------------------------------------------------------------------------
//
// A string tokenizer taken from http://www.sunsite.ualberta.ca/Documentation/
// /Gnu/libstdc++-2.90.8/html/21_strings/stringtok_std_h.txt
//
template <typename Container>
void stringtok (Container &container,
                std::string const &in,
                const char * const delimiters = " \t\n")
{
    const std::string::size_type len = in.length();
          std::string::size_type i = 0;

    while ( i < len )
    {
        // eat leading whitespace
        i = in.find_first_not_of (delimiters, i);

        if (i == std::string::npos)
            return;   // nothing left but white space

        // find the end of the token
        std::string::size_type j = in.find_first_of (delimiters, i);

        // push token
        if (j == std::string::npos)
        {
            container.push_back (in.substr(i));
            return;
        }
        else
            container.push_back (in.substr(i, j-i));

        // set up for next loop
        i = j + 1;
    }

    return;
}


//------------------------------------------------------------------------------
//
// Destructor: needed to delete temporary files
//
Gnuplot::~Gnuplot()
{
//  remove_tmpfiles();

    // A stream opened by popen() should be closed by pclose()
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__)
    if (_pclose(gnucmd) == -1)
#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
    if (pclose(gnucmd) == -1)
#endif
        throw GnuplotException("Problem closing communication to gnuplot");
}


//------------------------------------------------------------------------------
//
// Resets a gnuplot session (next plot will erase previous ones)
//
Gnuplot& Gnuplot::reset_plot()
{
//  remove_tmpfiles();

    nplots = 0;

    return *this;
}


//------------------------------------------------------------------------------
//
// resets a gnuplot session and sets all varibles to default
//
Gnuplot& Gnuplot::reset_all()
{
//  remove_tmpfiles();

    nplots = 0;
    cmd("reset");
    cmd("clear");
    pstyle = "points";
    smooth = "";
    showonscreen();

    return *this;
}


//------------------------------------------------------------------------------
//
// Change the plotting style of a gnuplot session
//
Gnuplot& Gnuplot::set_style(const std::string &stylestr)
{
    if (stylestr.find("lines")          == std::string::npos  &&
        stylestr.find("points")         == std::string::npos  &&
        stylestr.find("linespoints")    == std::string::npos  &&
        stylestr.find("impulses")       == std::string::npos  &&
        stylestr.find("dots")           == std::string::npos  &&
        stylestr.find("steps")          == std::string::npos  &&
        stylestr.find("fsteps")         == std::string::npos  &&
        stylestr.find("histeps")        == std::string::npos  &&
        stylestr.find("boxes")          == std::string::npos  &&  // 1-4 columns of data are required
        stylestr.find("filledcurves")   == std::string::npos  &&
        stylestr.find("vectors")        == std::string::npos  &&
		stylestr.find("histograms")     == std::string::npos  )   //only for one data column
//        stylestr.find("labels")         == std::string::npos  &&  // 3 columns of data are required
//        stylestr.find("xerrorbars")     == std::string::npos  &&  // 3-4 columns of data are required
//        stylestr.find("xerrorlines")    == std::string::npos  &&  // 3-4 columns of data are required
//        stylestr.find("errorbars")      == std::string::npos  &&  // 3-4 columns of data are required
//        stylestr.find("errorlines")     == std::string::npos  &&  // 3-4 columns of data are required
//        stylestr.find("yerrorbars")     == std::string::npos  &&  // 3-4 columns of data are required
//        stylestr.find("yerrorlines")    == std::string::npos  &&  // 3-4 columns of data are required
//        stylestr.find("boxerrorbars")   == std::string::npos  &&  // 3-5 columns of data are required
//        stylestr.find("xyerrorbars")    == std::string::npos  &&  // 4,6,7 columns of data are required
//        stylestr.find("xyerrorlines")   == std::string::npos  &&  // 4,6,7 columns of data are required
//        stylestr.find("boxxyerrorbars") == std::string::npos  &&  // 4,6,7 columns of data are required
//        stylestr.find("financebars")    == std::string::npos  &&  // 5 columns of data are required
//        stylestr.find("candlesticks")   == std::string::npos  &&  // 5 columns of data are required
//        stylestr.find("vectors")        == std::string::npos  &&
//        stylestr.find("image")          == std::string::npos  &&
//        stylestr.find("rgbimage")       == std::string::npos  &&
//        stylestr.find("pm3d")           == std::string::npos  )
    {
        pstyle = std::string("points");
    }
    else
    {
        pstyle = stylestr;
    }

    return *this;
}

Gnuplot& Gnuplot::set_lineStyle(const unsigned int styleNum, const unsigned int lineType, const unsigned int width, const std::string color){
	std::ostringstream cmdstr;

	cmdstr << "set style line " << styleNum << " lt " << lineType << " lc rgb \"" << color << "\" lw " << width;
	cmd(cmdstr.str());

	return *this;
}

//------------------------------------------------------------------------------
//
// smooth: interpolation and approximation of data
//
Gnuplot& Gnuplot::set_smooth(const std::string &stylestr)
{
    if (stylestr.find("unique")    == std::string::npos  &&
        stylestr.find("frequency") == std::string::npos  &&
        stylestr.find("csplines")  == std::string::npos  &&
        stylestr.find("acsplines") == std::string::npos  &&
        stylestr.find("bezier")    == std::string::npos  &&
        stylestr.find("sbezier")   == std::string::npos  )
    {
        smooth = "";
    }
    else
    {
        smooth = stylestr;
    }

    return *this;
}


//------------------------------------------------------------------------------
//
// sets terminal type to windows / x11
//
Gnuplot& Gnuplot::showonscreen()
{
    cmd("set output");
    cmd("set terminal " + Gnuplot::terminal_std);

    return *this;
}

//------------------------------------------------------------------------------
//
// saves a gnuplot session to a postscript file
//
Gnuplot& Gnuplot::savetops(const std::string &filename)
{
    cmd("set terminal postscript color");

    std::ostringstream cmdstr;
    cmdstr << "set output \"" << filename << ".ps\"";
    cmd(cmdstr.str());

    return *this;
}

//------------------------------------------------------------------------------
//
// Switches legend on
//
Gnuplot& Gnuplot::set_legend(const std::string &position)
{
    std::ostringstream cmdstr;
    cmdstr << "set key " << position;

    cmd(cmdstr.str());

    return *this;
}

//------------------------------------------------------------------------------
//
// turns on log scaling for the x axis
//
Gnuplot& Gnuplot::set_xlogscale(const double base)
{
    std::ostringstream cmdstr;

    cmdstr << "set logscale x " << base;
    cmd(cmdstr.str());

    return *this;
}

//------------------------------------------------------------------------------
//
// turns on log scaling for the y axis
//
Gnuplot& Gnuplot::set_ylogscale(const double base)
{
    std::ostringstream cmdstr;

    cmdstr << "set logscale y " << base;
    cmd(cmdstr.str());

    return *this;
}

//------------------------------------------------------------------------------
//
// turns on log scaling for the z axis
//
Gnuplot& Gnuplot::set_zlogscale(const double base)
{
    std::ostringstream cmdstr;

    cmdstr << "set logscale z " << base;
    cmd(cmdstr.str());

    return *this;
}

//------------------------------------------------------------------------------
//
// scales the size of the points used in plots
//
Gnuplot& Gnuplot::set_pointsize(const double pointsize)
{
    std::ostringstream cmdstr;
    cmdstr << "set pointsize " << pointsize;
    cmd(cmdstr.str());

    return *this;
}

//------------------------------------------------------------------------------
//
// set isoline density (grid) for plotting functions as surfaces
//
Gnuplot& Gnuplot::set_samples(const int samples)
{
    std::ostringstream cmdstr;
    cmdstr << "set samples " << samples;
    cmd(cmdstr.str());

    return *this;
}


//------------------------------------------------------------------------------
//
// set isoline density (grid) for plotting functions as surfaces
//
Gnuplot& Gnuplot::set_isosamples(const int isolines)
{
    std::ostringstream cmdstr;
    cmdstr << "set isosamples " << isolines;
    cmd(cmdstr.str());

    return *this;
}


//------------------------------------------------------------------------------
//
// enables contour drawing for surfaces set contour {base | surface | both}
//

Gnuplot& Gnuplot::set_contour(const std::string &position)
{
    if (position.find("base")    == std::string::npos  &&
        position.find("surface") == std::string::npos  &&
        position.find("both")    == std::string::npos  )
    {
        cmd("set contour base");
    }
    else
    {
        cmd("set contour " + position);
    }

    return *this;
}

//------------------------------------------------------------------------------
//
// set labels
//
// set the xlabel
Gnuplot& Gnuplot::set_xlabel(const std::string &label)
{
    std::ostringstream cmdstr;

    cmdstr << "set xlabel \"" << label << "\"";
    cmd(cmdstr.str());

    return *this;
}

//------------------------------------------------------------------------------
// set the ylabel
//
Gnuplot& Gnuplot::set_ylabel(const std::string &label)
{
    std::ostringstream cmdstr;

    cmdstr << "set ylabel \"" << label << "\"";
    cmd(cmdstr.str());

    return *this;
}

//------------------------------------------------------------------------------
// set the zlabel
//
Gnuplot& Gnuplot::set_zlabel(const std::string &label)
{
    std::ostringstream cmdstr;

    cmdstr << "set zlabel \"" << label << "\"";
    cmd(cmdstr.str());

    return *this;
}

//------------------------------------------------------------------------------
//
// set range
//
// set the xrange
Gnuplot& Gnuplot::set_xrange(const double iFrom,
                             const double iTo)
{
    std::ostringstream cmdstr;

    cmdstr << "set xrange[" << iFrom << ":" << iTo << "]";
    cmd(cmdstr.str());

    return *this;
}

//------------------------------------------------------------------------------
// set the yrange
//
Gnuplot& Gnuplot::set_yrange(const double iFrom,
                             const double iTo)
{
    std::ostringstream cmdstr;

    cmdstr << "set yrange[" << iFrom << ":" << iTo << "]";
    cmd(cmdstr.str());

    return *this;
}

//------------------------------------------------------------------------------
// set the zrange
//
Gnuplot& Gnuplot::set_zrange(const double iFrom,
                             const double iTo)
{
    std::ostringstream cmdstr;

    cmdstr << "set zrange[" << iFrom << ":" << iTo << "]";
    cmd(cmdstr.str());

    return *this;
}

//------------------------------------------------------------------------------
//
// set the palette range
//
Gnuplot& Gnuplot::set_cbrange(const double iFrom,
                              const double iTo)
{
    std::ostringstream cmdstr;

    cmdstr << "set cbrange[" << iFrom << ":" << iTo << "]";
    cmd(cmdstr.str());

    return *this;
}

//------------------------------------------------------------------------------
//
// Plots a linear equation y=ax+b (where you supply the
// slope a and intercept b)
//
Gnuplot& Gnuplot::plot_slope(const double a,
                             const double b,
                             const std::string &title)
{
    std::ostringstream cmdstr;
    //
    // command to be sent to gnuplot
    //
    if (nplots > 0  &&  two_dim == true)
        cmdstr << "replot ";
    else
        cmdstr << "plot ";

    cmdstr << a << " * x + " << b << " title \"";

    if (title == "")
        cmdstr << "f(x) = " << a << " * x + " << b;
    else
        cmdstr << title;

    cmdstr << "\" with " << pstyle;

    //
    // Do the actual plot
    //
    cmd(cmdstr.str());

    return *this;
}

//------------------------------------------------------------------------------
//
// Plot an equation supplied as a std::string y=f(x) (only f(x) expected)
//
Gnuplot& Gnuplot::plot_equation(const std::string &equation,
                                const std::string &title)
{
    std::ostringstream cmdstr;
    //
    // command to be sent to gnuplot
    //
    if (nplots > 0  &&  two_dim == true)
        cmdstr << "replot ";
    else
        cmdstr << "plot ";

    cmdstr << equation << " title \"";

    if (title == "")
        cmdstr << "f(x) = " << equation;
    else
        cmdstr << title;

    cmdstr << "\" with " << pstyle;

    //
    // Do the actual plot
    //
    cmd(cmdstr.str());

    return *this;
}

//------------------------------------------------------------------------------
//
// plot an equation supplied as a std::string y=(x)
//
Gnuplot& Gnuplot::plot_equation3d(const std::string &equation,
                                  const std::string &title)
{
    std::ostringstream cmdstr;
    //
    // command to be sent to gnuplot
    //
    if (nplots > 0  &&  two_dim == false)
        cmdstr << "replot ";
    else
        cmdstr << "splot ";

    cmdstr << equation << " title \"";

    if (title == "")
        cmdstr << "f(x,y) = " << equation;
    else
        cmdstr << title;

    cmdstr << "\" with " << pstyle;

    //
    // Do the actual plot
    //
    cmd(cmdstr.str());

    return *this;
}


//------------------------------------------------------------------------------
//
// Plots a 2d graph from a list of doubles (x) saved in a file
//
Gnuplot& Gnuplot::plotfile_x(const std::string &filename,
                             const unsigned int column,
                             const std::string &title)
{
    //
    // check if file exists
    //
    file_available(filename);


    std::ostringstream cmdstr;
    //
    // command to be sent to gnuplot
    //
    if (nplots > 0  &&  two_dim == true)
        cmdstr << "replot ";
    else
        cmdstr << "plot ";

    cmdstr << "\"" << filename << "\" using " << column;

    if (title == "")
        cmdstr << " notitle ";
    else
        cmdstr << " title \"" << title << "\" ";

    if(smooth == "")
        cmdstr << "with " << pstyle;
    else
        cmdstr << "smooth " << smooth;

    //
    // Do the actual plot
    //
    cmd(cmdstr.str()); //nplots++; two_dim = true;  already in cmd();

    return *this;
}



//------------------------------------------------------------------------------
//
// Plots a 2d graph from a list of doubles (x y) saved in a file
//
Gnuplot& Gnuplot::plotfile_xy(const std::string &filename,
                              const unsigned int column_x,
                              const unsigned int column_y,
                              const std::string &title,
							  const unsigned int linestyle)
{
    //
    // check if file exists
    //
    file_available(filename);


    std::ostringstream cmdstr;

    //
    // command to be sent to gnuplot
    //
    if (nplots > 0  &&  two_dim == true)
        cmdstr << "replot ";
    else
        cmdstr << "plot ";

    cmdstr << "\"" << filename << "\" using " << column_x << ":" << column_y;

    if (title == "")
        cmdstr << " notitle ";
    else
        cmdstr << " title \"" << title << "\" ";

    if(smooth == "")
        cmdstr << "with " << pstyle << " ls " << linestyle;
    else
        cmdstr << "smooth " << smooth;

    //
    // Do the actual plot
    //

    cmd(cmdstr.str());

    return *this;
}


//------------------------------------------------------------------------------
//
// Plots a 2d graph with errorbars from a list of doubles (x y dy) in a file
//
Gnuplot& Gnuplot::plotfile_xy_err(const std::string &filename,
                                  const unsigned int column_x,
                                  const unsigned int column_y,
                                  const unsigned int column_dy,
                                  const std::string &title)
{
    //
    // check if file exists
    //
    file_available(filename);

    std::ostringstream cmdstr;
    //
    // command to be sent to gnuplot
    //
    if (nplots > 0  &&  two_dim == true)
        cmdstr << "replot ";
    else
        cmdstr << "plot ";

    cmdstr << "\"" << filename << "\" using " 
           << column_x << ":" << column_y << ":" << column_dy 
           << " with errorbars ";

    if (title == "")
        cmdstr << " notitle ";
    else
        cmdstr << " title \"" << title << "\" ";

    //
    // Do the actual plot
    //
    cmd(cmdstr.str());

    return *this;
}


//------------------------------------------------------------------------------
//
// Plots a 3d graph from a list of doubles (x y z) saved in a file
//
Gnuplot& Gnuplot::plotfile_xyz(const std::string &filename,
                               const unsigned int column_x,
                               const unsigned int column_y,
                               const unsigned int column_z,
                               const std::string &title)
{
    //
    // check if file exists
    //
    file_available(filename);

    std::ostringstream cmdstr;
    //
    // command to be sent to gnuplot
    //
    if (nplots > 0  &&  two_dim == false)
        cmdstr << "replot ";
    else
        cmdstr << "splot ";

    cmdstr << "\"" << filename << "\" using " << column_x << ":" << column_y 
           << ":" << column_z;

    if (title == "")
        cmdstr << " notitle with " << pstyle;
    else
        cmdstr << " title \"" << title << "\" with " << pstyle;

    //
    // Do the actual plot
    //
    cmd(cmdstr.str());

    return *this;
}

Gnuplot& Gnuplot::plotfile_vectors(const std::string &filename,
								   const unsigned int column_x,
								   const unsigned int column_y,
								   const unsigned int column_dx,
								   const unsigned int column_dy,
                                   const std::string &title)
{
    //
    // check if file exists
    //
    file_available(filename);

    std::ostringstream cmdstr;
    //
    // command to be sent to gnuplot
    //

    if (nplots > 0  &&  two_dim == true)
        cmdstr << "replot ";
    else
        cmdstr << "plot ";

    cmdstr << "\"" << filename << "\" using " << column_x << ":" << column_y 
           << ":" << column_dx << ":" << column_dy;

    if (title == "")
        cmdstr << " notitle with " << pstyle << " ls 6";
    else
        cmdstr << " title \"" << title << "\" with " << pstyle;

    //
    // Do the actual plot
    //
    cmd(cmdstr.str());

    return *this;
}


//------------------------------------------------------------------------------
//
/// *  note that this function is not valid for versions of GNUPlot below 4.2
//
Gnuplot& Gnuplot::plot_image(const unsigned char * ucPicBuf,
                             const unsigned int iWidth,
                             const unsigned int iHeight,
                             const std::string &title)
{
    std::ofstream tmp;
    std::string name = create_tmpfile(tmp);
    if (name == "")
        return *this;

    //
    // write the data to file
    //
    int iIndex = 0;
    for(int iRow = 0; iRow < iHeight; iRow++)
    {
        for(int iColumn = 0; iColumn < iWidth; iColumn++)
        {
            tmp << iColumn << " " << iRow  << " " 
                << static_cast<float>(ucPicBuf[iIndex++]) << std::endl;
        }
    }

    tmp.flush();
    tmp.close();


    std::ostringstream cmdstr;
    //
    // command to be sent to gnuplot
    //
    if (nplots > 0  &&  two_dim == true)
        cmdstr << "replot ";
    else
        cmdstr << "plot ";

    if (title == "")
        cmdstr << "\"" << name << "\" with image";
    else
        cmdstr << "\"" << name << "\" title \"" << title << "\" with image";

    //
    // Do the actual plot
    //
    cmd(cmdstr.str());

    return *this;
}



//------------------------------------------------------------------------------
//
// Sends a command to an active gnuplot session
//
Gnuplot& Gnuplot::cmd(const std::string &cmdstr)
{
    if( !(valid) )
    {
        return *this;
    }


    // int fputs ( const char * str, FILE * stream );
    // writes the string str to the stream.
    // The function begins copying from the address specified (str) until it 
    // reaches the terminating null character ('\0'). This final 
    // null-character is not copied to the stream.
    fputs( (cmdstr+"\n").c_str(), gnucmd );

    // int fflush ( FILE * stream );
    // If the given stream was open for writing and the last i/o operation was 
    // an output operation, any unwritten data in the output buffer is written 
    // to the file.  If the argument is a null pointer, all open files are 
    // flushed.  The stream remains open after this call.
    fflush(gnucmd);


    if( cmdstr.find("replot") != std::string::npos )
    {
        return *this;
    }
    else if( cmdstr.find("splot") != std::string::npos )
    {
        two_dim = false;
        nplots++;
    }
    else if( cmdstr.find("plot") != std::string::npos )
    {
        two_dim = true;
        nplots++;
    }

    return *this;
}



//------------------------------------------------------------------------------
//
// Opens up a gnuplot session, ready to receive commands
//
void Gnuplot::init()
{
    // char * getenv ( const char * name );  get value of environment variable
    // Retrieves a C string containing the value of the environment variable 
    // whose name is specified as argument.  If the requested variable is not 
    // part of the environment list, the function returns a NULL pointer.
#if ( defined(unix) || defined(__unix) || defined(__unix__) ) && !defined(__APPLE__)
    if (getenv("DISPLAY") == NULL)
    {
        valid = false;
        throw GnuplotException("Can't find DISPLAY variable");
    }
#endif


    // if gnuplot not available
    if (!Gnuplot::get_program_path())
    {
        valid = false;
        throw GnuplotException("Can't find gnuplot");
    }


    //
    // open pipe
    //
    std::string tmp = Gnuplot::m_sGNUPlotPath + "/" + 
        Gnuplot::m_sGNUPlotFileName;

    // FILE *popen(const char *command, const char *mode);
    // The popen() function shall execute the command specified by the string 
    // command, create a pipe between the calling program and the executed 
    // command, and return a pointer to a stream that can be used to either read
    // from or write to the pipe.
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__)
    gnucmd = _popen(tmp.c_str(),"w");
#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
    gnucmd = popen(tmp.c_str(),"w");
#endif

    // popen() shall return a pointer to an open stream that can be used to read
    // or write to the pipe.  Otherwise, it shall return a null pointer and may 
    // set errno to indicate the error.
    if (!gnucmd)
    {
        valid = false;
        throw GnuplotException("Couldn't open connection to gnuplot");
    }

    nplots = 0;
    valid = true;
    smooth = "";

    //set terminal type
    showonscreen();

    return;
}


//------------------------------------------------------------------------------
//
// Find out if a command lives in m_sGNUPlotPath or in PATH
//
bool Gnuplot::get_program_path()
{
    //
    // first look in m_sGNUPlotPath for Gnuplot
    //
    std::string tmp = Gnuplot::m_sGNUPlotPath + "/" + 
        Gnuplot::m_sGNUPlotFileName;

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__)
    if ( Gnuplot::file_exists(tmp,0) ) // check existence
#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
    if ( Gnuplot::file_exists(tmp,1) ) // check existence and execution permission
#endif
    {
        return true;
    }


    //
    // second look in PATH for Gnuplot
    //
    char *path;
    // Retrieves a C string containing the value of environment variable PATH
    path = getenv("PATH");


    if (path == NULL)
    {
        throw GnuplotException("Path is not set");
        return false;
    }
    else
    {
        std::list<std::string> ls;

        //split path (one long string) into list ls of strings
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__)
        stringtok(ls,path,";");
#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
        stringtok(ls,path,":");
#endif

        // scan list for Gnuplot program files
        for (std::list<std::string>::const_iterator i = ls.begin(); 
                i != ls.end(); ++i)
        {
            tmp = (*i) + "/" + Gnuplot::m_sGNUPlotFileName;
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__)
            if ( Gnuplot::file_exists(tmp,0) ) // check existence
#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
            if ( Gnuplot::file_exists(tmp,1) ) // check existence and execution permission
#endif
            {
                Gnuplot::m_sGNUPlotPath = *i; // set m_sGNUPlotPath
                return true;
            }
        }

        tmp = "Can't find gnuplot neither in PATH nor in \"" + 
            Gnuplot::m_sGNUPlotPath + "\"";
        throw GnuplotException(tmp);

        Gnuplot::m_sGNUPlotPath = "";
        return false;
    }
}



//------------------------------------------------------------------------------
//
// check if file exists
//
bool Gnuplot::file_exists(const std::string &filename, int mode)
{
    if ( mode < 0 || mode > 7)
    {
        throw std::runtime_error("In function \"Gnuplot::file_exists\": mode\
                has to be an integer between 0 and 7");
        return false;
    }

    // int _access(const char *path, int mode);
    //  returns 0 if the file has the given mode,
    //  it returns -1 if the named file does not exist or is not accessible in 
    //  the given mode
    // mode = 0 (F_OK) (default): checks file for existence only
    // mode = 1 (X_OK): execution permission
    // mode = 2 (W_OK): write permission
    // mode = 4 (R_OK): read permission
    // mode = 6       : read and write permission
    // mode = 7       : read, write and execution permission
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__)
    if (_access(filename.c_str(), mode) == 0)
#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
    if (access(filename.c_str(), mode) == 0)
#endif
    {
        return true;
    }
    else
    {
        return false;
    }

}

bool Gnuplot::file_available(const std::string &filename){
    std::ostringstream except;
    if( Gnuplot::file_exists(filename,0) ) // check existence
    {
        if( !(Gnuplot::file_exists(filename,4)) ){// check read permission
            except << "No read permission for File \"" << filename << "\"";
            throw GnuplotException( except.str() );
            return false;
        }
    }
    else{
        except << "File \"" << filename << "\" does not exist";
        throw GnuplotException( except.str() );
        return false;
    }
}



//------------------------------------------------------------------------------
//
// Opens a temporary file
//
std::string Gnuplot::create_tmpfile(std::ofstream &tmp)
{

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__)
    char name[] = "gnuplotiXXXXXX"; //tmp file in working directory
#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
    char name[] = "/tmp/gnuplotiXXXXXX"; // tmp file in /tmp
#endif

    //
    // check if maximum number of temporary files reached
    //
    if (Gnuplot::tmpfile_num == GP_MAX_TMP_FILES - 1)
    {
        std::ostringstream except;
        except << "Maximum number of temporary files reached (" 
               << GP_MAX_TMP_FILES << "): cannot open more files" << std::endl;

        throw GnuplotException( except.str() );
        return "";
    }

    // int mkstemp(char *name);
    // shall replace the contents of the string pointed to by "name" by a unique
    // filename, and return a file descriptor for the file open for reading and 
    // writing.  Otherwise, -1 shall be returned if no suitable file could be 
    // created.  The string in template should look like a filename with six 
    // trailing 'X' s; mkstemp() replaces each 'X' with a character from the 
    // portable filename character set.  The characters are chosen such that the
    // resulting name does not duplicate the name of an existing file at the 
    // time of a call to mkstemp()


    //
    // open temporary files for output
    //
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__)
    if (_mktemp(name) == NULL)
#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
    if (mkstemp(name) == -1)
#endif
    {
        std::ostringstream except;
        except << "Cannot create temporary file \"" << name << "\"";
        throw GnuplotException(except.str());
        return "";
    }

    tmp.open(name);
    if (tmp.bad())
    {
        std::ostringstream except;
        except << "Cannot create temporary file \"" << name << "\"";
        throw GnuplotException(except.str());
        return "";
    }

    //
    // Save the temporary filename
    //
    tmpfile_list.push_back(name);
    Gnuplot::tmpfile_num++;

    return name;
}

void Gnuplot::remove_tmpfiles(){
    if ((tmpfile_list).size() > 0)
    {
        for (unsigned int i = 0; i < tmpfile_list.size(); i++)
            remove( tmpfile_list[i].c_str() );

        Gnuplot::tmpfile_num -= tmpfile_list.size();
    }
}
#endif
